package com.free.chat.netty;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.free.chat.common.enums.MsgActionEnum;
import com.free.chat.entity.model.ChatMsg;
import com.free.chat.service.ChatMsgService;
import com.free.chat.service.impl.ChatMsgServiceImpl;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.noear.solon.Solon;

import java.util.ArrayList;
import java.util.List;

public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    //用户记录和管理所有客户端的channel
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    public ChatMsgService chatMsgService = Solon.cfg()
            .getBean("chatMsgService", ChatMsgServiceImpl.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // TODO: 2022/10/21 客户端消息传输
        //获取客户端传输的消息
        String content = msg.text();
        Channel currentChannel = ctx.channel();

        // 1. 获取客户端发来的消息
        DataContent dataContent = JSONUtil.toBean(content, DataContent.class);
        Integer action = dataContent.getAction();

        // 2. 判断消息类型，根据不同的类型来处理不同的业务
        if (action.equals(MsgActionEnum.CONNECT.type)) {
            // 	2.1  当websocket 第一次open的时候，初始化channel，把用的channel和userid关联起来
            Long senderId = dataContent.getChatRecord().getSendUserId();
            UserChannelRel.put(senderId, currentChannel);

            // 测试
            for (Channel c : clients) {
                System.out.println(c.id().asLongText());
            }
            UserChannelRel.output();
        } else if (action.equals(MsgActionEnum.CHAT.type)) {
            ChatRecord chatRecord = dataContent.getChatRecord();
            String msg1 = chatRecord.getMsg();
            Long senderId = chatRecord.getSendUserId();
            Long receiverId = chatRecord.getAcceptUserId();
            // 保存消息到数据库，并且标记为 未签收
            Long msgId = chatMsgService.saveMsgRecord(chatRecord);
            chatRecord.setMsgId(msgId);
            DataContent dataContentMsg = new DataContent();
            dataContentMsg.setChatRecord(chatRecord);

            // 发送消息
            // 从全局用户Channel关系中获取接受方的channel
            Channel receiverChannel = UserChannelRel.get(receiverId);
            if (receiverChannel == null) {
                // TODO channel为空代表用户离线，推送消息（JPush，个推，小米推送）
            } else {
                String dataContentMsg1 = JSONUtil.toJsonStr(dataContent);
                // 当receiverChannel不为空的时候，从ChannelGroup去查找对应的channel是否存在
                Channel findChannel = clients.find(receiverChannel.id());
                if (findChannel != null) {
                    // 用户在线
                    receiverChannel.writeAndFlush(new TextWebSocketFrame(dataContentMsg1));
                } else {
                    // 用户离线 TODO 推送消息
                }
            }
        } else if (action.equals(MsgActionEnum.SIGNED.type)) {
            //  2.3  签收消息类型，针对具体的消息进行签收，修改数据库中对应消息的签收状态[已签收]
            // 扩展字段在signed类型的消息中，代表需要去签收的消息id，逗号间隔
            String msgIdsStr = dataContent.getExtension();
            String[] msgIds = msgIdsStr.split(",");

            List<ChatMsg> chatMsgList = new ArrayList<>();
            for (String mid : msgIds) {
                if (StrUtil.isNotBlank(mid)) {
                    ChatMsg chatMsg = new ChatMsg();
                    chatMsg.setId(Long.parseLong(mid));
                    chatMsg.setSignFlag(1);
                    chatMsgList.add(chatMsg);
                }
            }

            if (!chatMsgList.isEmpty()) {
                // 批量签收
                chatMsgService.updateBatchById(chatMsgList);
            }
        }
    }

    /**
     * @Description: 当客户端连接服务端之后, 获取到客户端的channel, 并且放到channelGroup中
     * @Param: ctx
     * @return:
     * @Author: 朝花不迟暮
     * @Date: 2020/12/28
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        clients.add(channel);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        clients.remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        // 发生异常之后关闭连接（关闭channel），随后从ChannelGroup中移除
        ctx.channel().close();
        clients.remove(ctx.channel());
    }
}
